/*******************************************************************************
 *
 * File Name:          Functions.java
 *
 * Created:            2006-10-16 20:57:21
 *
 * Original Author:    yu.peng
 *
 *------------------------------------------------------------------------------
 * MODIFICATION HISTORY
 *------------------------------------------------------------------------------
 * WHEN                WHO                 WHY
 * 2006-10-16 20:57:21 yu.peng             new
 *------------------------------------------------------------------------------
 *
 ******************************************************************************/
/*******************/
/* PACKAGE SECTION */
/*******************/
package org.njo.webapp.root.taglib;

import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.njo.commons.lang.StringUtil;

/**
 * Web Root标准Taglib库.
 * 
 * @author yu.peng
 * @version 0.01
 */
public class Functions {

    // 在windows,unix(linux)操作系统下的路径分隔符
    public static final char[] FILE_SEPARATOR = { '\\', '/' };

    /**
     * 分析处理请求,并将请求参数置入Map中放回. 返回值为null时,上传请求处理失败. <p/> 注意:
     * 1,如果上传请求时,将上传的文件保存到临时文件中.
     * 2,这个方法只能处理单个[fieldName]参数的请求.也就是说提交的表单中参数应该时唯一的.
     */
    public static Map parseRequest(HttpServletRequest request) {
        // 判断是否是文件上传.
        String contentTypeHeader = request.getContentType();
        boolean isMultipart = (contentTypeHeader != null)
                && (contentTypeHeader.startsWith("multipart/form-data"));
        // 如果文件上传的情况下
        if (isMultipart) {
            // 分析请求并缓存上传内容.
            return parseMultiRequest(request);
        } else {
            Map input = new HashMap();
            Enumeration enu = request.getParameterNames();
            while (enu.hasMoreElements()) {
                String parameterName = (String) enu.nextElement();
                input.put(parameterName, request.getParameter(parameterName));
            }
            return input;
        }
    }

    /**
     * 处理文件上传. <p/> 1,分析请求,返回请求参数Map. 2,将上传的文件会被放到缓存(临时文件)中.
     */
    static Map parseMultiRequest(HttpServletRequest request) {
        try {
            Map reqMap = new HashMap();
            DiskFileUpload fu = new DiskFileUpload();
            // 设置允许用户上传文件大小,单位:字节
            fu.setSizeMax(1024 * 1024 * 10);
            // 设置最多只允许在内存中存储的数据,单位:字节
            fu.setSizeThreshold(4096);
            // 设定编码集
            fu.setHeaderEncoding("utf-8");
            // 开始读取上传信息
            List fileItems = fu.parseRequest(request);
            for (int i = 0; i < fileItems.size(); i++) {
                FileItem item = (FileItem) fileItems.get(i);
                if (item.isFormField()) {
                    reqMap.put(item.getFieldName(), item.getString());
                } else {
                    reqMap.put(item.getFieldName(), item);
                }
            }
            return reqMap;
        } catch (FileUploadException e) {
            return null;
        }
    }

    /**
     * 根据指定的路径,取得文件名.
     * 
     * @param path
     *            文件路径
     * @return 文件名
     */
    static String getFileName(String path) {
        if (path == null) {
            return null;
        }

        StringBuffer sb = new StringBuffer();
        int length = path.length();
        if (endsWithSeparator(path)) {
            length--;
        }
        for (int i = length - 1; i > 0; i--) {
            char c = path.charAt(i);
            if (isSeparator(c)) {
                break;
            }
            sb.insert(0, c);
        }
        return sb.toString();
    }

    /**
     * 判定指定的字符是否是路径分隔符.
     * 
     * @param c
     * @return boolean
     */
    static boolean isSeparator(char c) {
        for (int i = 0; i < FILE_SEPARATOR.length; i++) {
            if (c == FILE_SEPARATOR[i]) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判定指定的路径是否以路径分割符结尾.
     * 
     * @param path
     * @return boolean
     */
    static boolean endsWithSeparator(String path) {
        if (path == null) {
            return false;
        }
        for (int i = 0; i < FILE_SEPARATOR.length; i++) {
            if (path.endsWith(String.valueOf(FILE_SEPARATOR[i]))) {
                return true;
            }
        }
        return false;
    }

    /**
     * 保存上传的文件(FileIem)到磁盘的指定路径中.
     * 
     * @param fileItem
     * @param path
     * @return true:保存成功
     */
    public static boolean saveFileItem(FileItem fileItem, String path) {
        // retrieve the file representation
        try {
            // TODO:取得文件名
            // String fileName = file.getName();
            String fileName = "zzz.xml";
            File toFile = new File(path, fileName);
            // retrieve the file data
            InputStream stream = fileItem.getInputStream();
            // write the file to the file specified
            OutputStream bos = new FileOutputStream(toFile);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = stream.read(buffer, 0, 8192)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }
            bos.close();
            stream.close();
            return true;
        } catch (IOException ioe) {
            return false;
        }
    }

    /**
     * 判定指定的集合中是否包含指定的元素.
     * 
     * @param obj
     * @param targetCollection
     * @return true
     */
    public static boolean contains(Object obj, Object targetCollection) {
        if (targetCollection == null) {
            return false;
        }

       if (targetCollection instanceof Object[]) {
            Object[] array = (Object[]) targetCollection;
            // TODO:Arrays.binarySearch(array, obj);
            for (int i = 0; i < array.length; i++) {
                Object o = array[i];
                if (o == obj || obj.equals(o)) {
                    return true;
                }
            }
        } else if (targetCollection instanceof Collection) {
            Collection col = (Collection) targetCollection;
            return col.contains(obj);
        }

        return false;
    }

    /**
     * 取得指定Object的长度.
     * 
     * @param obj
     * @return
     */
    public static int length(Object obj) {
        if (obj == null) {
            return 0;
        } else if (obj instanceof String) {
            return ((String)obj).length();
        } else if (obj instanceof Object[]) {
            return ((Object[]) obj).length;
        } else if (obj instanceof Collection) {
            return ((Collection) obj).size();
        } else if (obj instanceof Map) {
            return ((Map) obj).size();
        } else {
            return 0;
        }
    }
    
    
    /**
     * 判定指定的对象是否为空.
     * 
     * null:返回true String实例:""返回true Collection实例:集合中没有元素存在时返回true
     * Map实例:集合中没有元素存在时返回true
     * 
     * @param o
     * @return
     * @throws JspException
     */
    public static boolean isEmpty(Object o) {
        return length(o)==0;
//        if (o == null) {
//            return true;
//        }
//        if (o instanceof String) {
//            if ("".equals(o)) {
//                return true;
//            }
//            return false;
//        }
//        if (o instanceof Object[]) {
//            return ((Object[]) o).length == 0;
//        } else if (o instanceof Collection) {
//            return ((Collection) o).isEmpty();
//        } else if (o instanceof Map) {
//            return ((Map) o).isEmpty();
//        } else {
//            return false;
//        }
    }
    
    /**
     * 将指定的对象转换成 javascript的Object类型.
     * 
     * @param obj
     * @return
     */
    public static String toJsObject(Object obj) {
        StringBuffer sb = new StringBuffer();
        toJsObject(sb, obj);
        return sb.toString();
    }
    
    /**
     * 递归转换javascript Object数据.
     * 
     * @param sb
     * @param obj
     */
    private static void toJsObject(StringBuffer sb, Object obj) {
        if (obj == null) {
            sb.append("null");
        } else if (obj instanceof String) {
            sb.append("\"");
            sb.append(StringUtil.escapeStringCharacters((String)obj));
            sb.append("\"");
        } else if (obj instanceof Date) {
            sb.append(((Date)obj).getTime());
        } else if (obj instanceof Object[]) {
            Object[] arr = (Object[])obj;
            sb.append("[");
            for (int i = 0; i < arr.length; i++) {
                toJsObject(sb, arr[i]);
                if (i!=arr.length-1) {
                    sb.append(",");
                }
            }
            sb.append("]");
        } else if (obj instanceof Collection) {
            Collection coll = (Collection) obj;
            Iterator iterator = coll.iterator();
            sb.append("[");
            while (iterator.hasNext()) {
                toJsObject(sb, iterator.next());
                if (iterator.hasNext()) {
                    sb.append(",");
                }
            }
            sb.append("]");
        } else if (obj instanceof Map.Entry) {
            Map.Entry entry = (Map.Entry)obj;
            toJsObject(sb, entry.getKey());
            sb.append(":");
            toJsObject(sb, entry.getValue());
        } else if (obj instanceof InstanceProperty) {
            InstanceProperty entry = (InstanceProperty)obj;
            toJsObject(sb, entry.getName());
            sb.append(":");
            toJsObject(sb, entry.getValue());
        } else if (obj instanceof Map) {
            Map map = (Map)obj;
            Iterator iterator = map.entrySet().iterator();
            sb.append("{");
            while (iterator.hasNext()) {
                toJsObject(sb, iterator.next());
                if (iterator.hasNext()) {
                    sb.append(",");
                }
            }
            sb.append("}");
        } else {
            PropertyDescriptor[] objDescriptors = PropertyUtils.getPropertyDescriptors(obj);
            List readableDescriptorList = new ArrayList();
            for (int i = 0; i < objDescriptors.length; i++) {
                String name = objDescriptors[i].getName();
                if ("class".equals(name)) {
                    continue; // No point in trying to set an object's class
                }
                if (PropertyUtils.isReadable(obj, name)) {
                    try {
                        Object value =  PropertyUtils.getSimpleProperty(obj, name);
                        readableDescriptorList.add(new InstanceProperty(name, value));
                    } catch (NoSuchMethodException e) {
                        ; // Should not happen
                    } catch (InvocationTargetException e) {
                        ;
                    } catch (IllegalAccessException e) {
                        ;
                    }
                }
            }
            
            if (readableDescriptorList.isEmpty()) {
                sb.append(String.valueOf(obj));
            } else {
                sb.append("{");
                for (int i = 0; i < readableDescriptorList.size(); i++) {
                    InstanceProperty pro = (InstanceProperty)readableDescriptorList.get(i);
                    toJsObject(sb, pro);
                    if (i!=readableDescriptorList.size()-1) {
                        sb.append(",");
                    }
                }
                sb.append("}");
            }
        }
    }
    
    static class InstanceProperty {
        String name = null;
        Object value = null;
        InstanceProperty(String name, Object obj) {
            this.name = name;
            this.value = obj;
        }
        public String getName() {
            return name;
        }
        public Object getValue() {
            return value;
        }
    }
    
    

    /**
     * 判定指定的request的用户是否是指定的角色.
     * 
     * @param request
     * @param roles
     * @return
     */
    public static boolean isUserInRole(HttpServletRequest request, String roles) {
        return request.isUserInRole(roles);
    }

    /**
     * 在每一行前加入指定字符作为前缀.
     * 
     * @param text
     * @param prefix
     * @return 修改后的结果
     */
    public static String fixpreOfLine(String text, String prefix) {
        if (text == null) {
            return null;
        }

        if (prefix == null) {
            return text;
        }

        StringBuffer sb = new StringBuffer();
        List lineData = StringUtil.split(text, "\n");
        for (int i = 0; i < lineData.size(); i++) {
            String s = (String) lineData.get(i);
            sb.append(prefix);
            sb.append(s);
        }
        return sb.toString();
    }
}

